﻿/*************************************************************************
 * Created by OhZee Creative, LLC
 * 2013
 * This code is licensed under Microsoft Public License (Ms-PL)
 * http://opensource.org/licenses/ms-pl
 * http://ozcontrols.codeplex.com/
 *************************************************************************/

namespace OhZeeCreative.Windows8.UI.Lynyrd
{
    using OhZeeCreative.Helpers;
    using System;
    using Windows.Foundation;
    using Windows.UI;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Media.Animation;

    public sealed class AppBarFlyoutButton : Button
    {
        private readonly Popup popup;
        public Popup Popup { get { return this.popup; } }
        private readonly Point zeroPoint = new Point();

        public AppBarFlyoutButton()
        {
            this.DefaultStyleKey = typeof(AppBarFlyoutButton);

            this.popup = new Popup()
            {
                IsLightDismissEnabled = this.IsLightDismissEnabled
            };

            this.Click += AppBarFlyoutButton_Click;
        }

        private void AppBarFlyoutButton_Click(object sender, RoutedEventArgs e)
        {
            FrameworkElement dob = sender as FrameworkElement;
            if (dob != null)
            {
                this.popup.DataContext = dob.DataContext;
            }
            this.Open();
        }

        public static readonly DependencyProperty OffsetVerticalProperty = DependencyProperty.Register("OffsetVertical", typeof(double), typeof(AppBarFlyoutButton), new PropertyMetadata(double.NaN));
        public static readonly DependencyProperty GapWithAppBarProperty = DependencyProperty.Register("GapWithAppBar", typeof(double), typeof(AppBarFlyoutButton), new PropertyMetadata(0.0)); 
        public static readonly DependencyProperty FlyoutTemplateProperty = DependencyProperty.Register("FlyoutTemplate", typeof(DataTemplate), typeof(AppBarFlyoutButton), new PropertyMetadata(null));
        public static readonly DependencyProperty FlyoutWidthProperty = DependencyProperty.Register("FlyoutWidth", typeof(double), typeof(AppBarFlyoutButton), new PropertyMetadata(double.NaN));
        public static readonly DependencyProperty FlyoutHeightProperty = DependencyProperty.Register("FlyoutHeight", typeof(double), typeof(AppBarFlyoutButton), new PropertyMetadata(double.NaN));
        public static readonly DependencyProperty IsLightDismissEnabledProperty = DependencyProperty.Register("IsLightDismissEnabled", typeof(bool), typeof(AppBarFlyoutButton), new PropertyMetadata(true, IsLightDismissEnabledPropertyChanged));

        private static void IsLightDismissEnabledPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
        {
            AppBarFlyoutButton appBarFlyoutButton = (AppBarFlyoutButton)o;
            appBarFlyoutButton.popup.IsLightDismissEnabled = (bool) args.NewValue;
        }
        
        public double OffsetVertical
        {
            get { return (double)GetValue(OffsetVerticalProperty); }
            set { SetValue(OffsetVerticalProperty, value); }
        }

        public double GapWithAppBar
        {
            get { return (double)GetValue(GapWithAppBarProperty); }
            set { SetValue(GapWithAppBarProperty, value); }
        }

        public DataTemplate FlyoutTemplate
        {
            get { return (DataTemplate)GetValue(FlyoutTemplateProperty); }
            set { SetValue(FlyoutTemplateProperty, value); }
        }

        public double FlyoutWidth
        {
            get { return (double)GetValue(FlyoutWidthProperty); }
            set { SetValue(FlyoutWidthProperty, value); }
        }

        public double FlyoutHeight
        {
            get { return (double)GetValue(FlyoutHeightProperty); }
            set { SetValue(FlyoutHeightProperty, value); }
        }

        public bool IsLightDismissEnabled
        {
            get { return (bool)GetValue(IsLightDismissEnabledProperty); }
            set { SetValue(IsLightDismissEnabledProperty, value); }
        }

        public bool IsDebugBackgroundEnabled { get; set; }

        private void Open()
        {
            // If it's already open
            if (this.popup.IsOpen)
            {
                if (!this.popup.IsLightDismissEnabled)
                {
                    // Close it
                    this.popup.IsOpen = false;
                }
                return;
            }
                        
            if (this.FlyoutTemplate == null)
            {
                return;
            }
            
	        FrameworkElement flyoutContent = this.FlyoutTemplate.LoadContent() as FrameworkElement;
            if (flyoutContent == null)
            {
                return;
            }
            

            AppBar appBar = LayoutHelper.GetAncestor<AppBar>(this);

            Page page = null;
            Frame frame = Window.Current.Content as Frame;
            if (frame != null)
            {
                page = frame.Content as Page;
            }

            if (page == null || appBar == null)
            {
                throw new InvalidOperationException("AppBarFlyoutButton is only supported inside a top or bottom AppBar in a Page");
            }

            bool isBottomAppBar = page.BottomAppBar == appBar;

            flyoutContent.VerticalAlignment = isBottomAppBar ? VerticalAlignment.Bottom : VerticalAlignment.Top;

            double flyoutWidth = double.IsNaN(this.FlyoutWidth) ? (double.IsNaN(flyoutContent.Width) ? 200.0 : flyoutContent.Width) : this.FlyoutWidth;
            double flyoutHeight = double.IsNaN(this.FlyoutHeight) ? (double.IsNaN(flyoutContent.Height) ? page.ActualHeight : flyoutContent.Height) : this.FlyoutHeight;
                        
            Grid container = new Grid() { 
                Width = flyoutWidth,
                Height = flyoutHeight, 
                Transitions = new TransitionCollection(),                
            };

            if (this.IsDebugBackgroundEnabled)
            {
                GradientStopCollection gsc = new GradientStopCollection();
                gsc.Add(new GradientStop() { Offset = 0.0, Color = Color.FromArgb(0x80, 0xFF, 0xFF, 0xFF) });
                gsc.Add(new GradientStop() { Offset = 1.0, Color = Color.FromArgb(0x80, 0x00, 0x00, 0x00) });

                container.Background = new LinearGradientBrush(gsc, 45.0);
            }
            container.Children.Add(flyoutContent);

            this.popup.Child = container;

            GeneralTransform buttonTransformRelativeToAppbar = this.TransformToVisual(appBar);
            double leftOfButton = buttonTransformRelativeToAppbar.TransformPoint(zeroPoint).X;
            
            double leftOfFlyout = leftOfButton + (this.ActualWidth - flyoutWidth) * 0.5;
            double rightOfFlyout = leftOfFlyout + flyoutWidth;

            // HACK: Doesn't propertly cover all the cases
            if (leftOfFlyout >= 0 && rightOfFlyout <= page.ActualWidth)
            {
                popup.HorizontalOffset = leftOfFlyout;
            }
            else if (leftOfFlyout < 0)
            {
                popup.HorizontalOffset = 0;
            }
            else if (rightOfFlyout > page.ActualWidth)
            {
                popup.HorizontalOffset = page.ActualWidth - flyoutWidth;
            }

            GeneralTransform appBarTransformRelativeToPage = appBar.TransformToVisual(page);
            double topOfAppBar = appBarTransformRelativeToPage.TransformPoint(zeroPoint).Y;

            popup.VerticalOffset = isBottomAppBar ? topOfAppBar - flyoutHeight - this.GapWithAppBar : topOfAppBar + appBar.ActualHeight + this.GapWithAppBar;

            double transitionOffset;
            if (double.IsNaN(this.OffsetVertical))
            {
                transitionOffset = isBottomAppBar ? appBar.ActualHeight * 0.5 : appBar.ActualHeight * -0.5;
            }
            else
            {
                transitionOffset = this.OffsetVertical;
            }

            popup.Child.Transitions.Add(new PopupThemeTransition() { FromVerticalOffset = transitionOffset });

            popup.IsOpen = true;
        }
    }
}
